package edu.sdjzu.exam.service.exam.impl;

import cn.dev33.satoken.stp.StpUtil;
import edu.sdjzu.exam.domain.exam.ExamAnswer;
import edu.sdjzu.exam.domain.exam.ExamQuestion;
import edu.sdjzu.exam.domain.exam.StudentGrade;
import edu.sdjzu.exam.dto.GradingDTO;
import edu.sdjzu.exam.enums.GradeStatus;
import edu.sdjzu.exam.mapper.exam.ExamAnswersMapper;
import edu.sdjzu.exam.mapper.exam.ExamQuestionsMapper;
import edu.sdjzu.exam.mapper.exam.StudentGradesMapper;
import edu.sdjzu.exam.service.exam.GradingService;
import edu.sdjzu.exam.service.exam.AutoGradingService;
import edu.sdjzu.exam.service.exam.AutoGradingService.AutoGradingResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@Service
@RequiredArgsConstructor
public class GradingServiceImpl implements GradingService {

    private final ExamAnswersMapper examAnswersMapper;
    private final ExamQuestionsMapper examQuestionsMapper;
    private final StudentGradesMapper studentGradesMapper;
    private final AutoGradingService autoGradingService;

    @Override
    public List<GradingDTO.ExamGradingListDTO> getExamsNeedingGrading() {
        log.info("获取需要批改的考试列表");

        List<Map<String, Object>> examData = studentGradesMapper.selectExamsNeedingGrading();
        
        return examData.stream().map(row -> {
            GradingDTO.ExamGradingListDTO dto = new GradingDTO.ExamGradingListDTO();
            dto.setExamId((Long) row.get("exam_id"));
            dto.setExamTitle((String) row.get("exam_title"));
            dto.setTotalStudents(((Number) row.get("total_students")).intValue());
            dto.setPendingStudents(((Number) row.get("pending_students")).intValue());
            dto.setCompletedStudents(((Number) row.get("completed_students")).intValue());
            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public List<GradingDTO.StudentGradingListDTO> getStudentsForGrading(Long examId) {
        log.info("获取考试 {} 的考生批改列表", examId);
        
        List<Map<String, Object>> gradeData = studentGradesMapper.selectGradesWithStudentNamesByExamId(examId);
        
        return gradeData.stream().map(row -> {
            GradingDTO.StudentGradingListDTO dto = new GradingDTO.StudentGradingListDTO();
            dto.setStudentId((Long) row.get("student_id"));
            dto.setStudentName((String) row.get("student_name"));
            dto.setGradeStatus((String) row.get("grade_status"));
            dto.setCurrentScore((BigDecimal) row.get("current_score"));
            dto.setSubmitTime(row.get("submit_time") != null ? row.get("submit_time").toString() : null);
            
            // 统计主观题数量
            Long studentId = (Long) row.get("student_id");
            int totalSubjective = examAnswersMapper.countTotalSubjectiveAnswers(examId, studentId);
            int gradedSubjective = examAnswersMapper.countGradedSubjectiveAnswers(examId, studentId);
            dto.setTotalSubjectiveQuestions(totalSubjective);
            dto.setGradedQuestions(gradedSubjective);
            
            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public List<GradingDTO.SubjectiveAnswerDTO> getSubjectiveAnswers(Long examId, Long studentId) {
        log.info("获取学生 {} 在考试 {} 中的主观题答案", studentId, examId);
        
        List<Map<String, Object>> subjectiveAnswers = examAnswersMapper.selectSubjectiveAnswersByExamAndStudent(examId, studentId);
        log.info("查询到 {} 条主观题答案记录", subjectiveAnswers.size());
        
        if (subjectiveAnswers.isEmpty()) {
            log.warn("学生 {} 在考试 {} 中没有找到主观题答案，检查数据库记录", studentId, examId);
            // 检查是否有任何答案记录
            int totalAnswers = examAnswersMapper.countAnswersByExamAndStudent(examId, studentId);
            log.info("学生 {} 在考试 {} 中总共有 {} 条答案记录", studentId, examId, totalAnswers);
        }
        
        return subjectiveAnswers.stream().map(row -> {
            GradingDTO.SubjectiveAnswerDTO dto = new GradingDTO.SubjectiveAnswerDTO();
            dto.setAnswerId((Long) row.get("answer_id"));
            dto.setQuestionId((Long) row.get("question_id"));
            dto.setQuestionContent((String) row.get("question_content"));
            dto.setQuestionType((String) row.get("question_type"));
            dto.setReferenceAnswer((String) row.get("reference_answer"));
            dto.setPoints((BigDecimal) row.get("points"));
            dto.setMaxScore((BigDecimal) row.get("points")); // 设置maxScore为题目分值
            dto.setAnswerContent((String) row.get("answer_content"));
            dto.setFilePath((String) row.get("file_path"));
            dto.setScore((BigDecimal) row.get("score"));
            dto.setComment((String) row.get("comment"));
            dto.setMarkedBy((Long) row.get("marked_by"));
            dto.setMarkedByName((String) row.get("marked_by_name"));
            
            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public List<GradingDTO.SubjectiveAnswerDTO> getSubjectiveAnswersBySession(Long sessionId) {
        log.info("通过sessionId {} 获取主观题答案", sessionId);
        
        List<Map<String, Object>> subjectiveAnswers = examAnswersMapper.selectSubjectiveAnswersBySession(sessionId);
        
        return subjectiveAnswers.stream().map(row -> {
            GradingDTO.SubjectiveAnswerDTO dto = new GradingDTO.SubjectiveAnswerDTO();
            dto.setAnswerId((Long) row.get("answer_id"));
            dto.setQuestionId((Long) row.get("question_id"));
            dto.setQuestionContent((String) row.get("question_content"));
            dto.setQuestionType((String) row.get("question_type"));
            dto.setReferenceAnswer((String) row.get("reference_answer"));
            dto.setPoints((BigDecimal) row.get("points"));
            dto.setAnswerContent((String) row.get("answer_content"));
            dto.setFilePath((String) row.get("file_path"));
            dto.setScore((BigDecimal) row.get("score"));
            dto.setComment((String) row.get("comment"));
            dto.setMarkedBy((Long) row.get("marked_by"));
            dto.setMarkedByName((String) row.get("marked_by_name"));
            
            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void gradeSingleAnswer(GradingDTO gradingDTO) {
        Long teacherId = StpUtil.getLoginIdAsLong();
        log.info("教师 {} 批改答案 {}", teacherId, gradingDTO.getAnswerId());
        
        // 1. 验证答案是否存在
        ExamAnswer answer = examAnswersMapper.selectAnswerById(gradingDTO.getAnswerId());
        if (answer == null) {
            throw new RuntimeException("答案不存在，答案ID: " + gradingDTO.getAnswerId());
        }
        
        // 2. 获取题目分值进行验证
        ExamQuestion examQuestion = examQuestionsMapper.selectExamQuestionByExamAndQuestion(
                answer.getExamId(), answer.getQuestionId());
        if (examQuestion == null) {
            throw new RuntimeException("考试题目配置不存在");
        }
        
        // 3. 验证分数不能超过题目满分
        if (gradingDTO.getScore().compareTo(examQuestion.getScore()) > 0) {
            throw new RuntimeException("分数不能超过题目满分 " + examQuestion.getScore());
        }
        
        // 4. 检查答案是否已被其他教师批改（并发控制）
        ExamAnswer currentAnswer = examAnswersMapper.selectAnswerById(gradingDTO.getAnswerId());
        if (currentAnswer.getMarkedBy() != null && !currentAnswer.getMarkedBy().equals(teacherId)) {
            log.warn("答案已被其他教师批改，答案ID: {}, 当前批改者: {}, 尝试批改者: {}", 
                    gradingDTO.getAnswerId(), currentAnswer.getMarkedBy(), teacherId);
            throw new RuntimeException("该答案已被其他教师批改，请刷新页面查看最新状态");
        }
        
        // 5. 更新答案分数
        examAnswersMapper.updateAnswerScore(
                gradingDTO.getAnswerId(),
                gradingDTO.getScore(),
                teacherId,
                LocalDateTime.now(),
                gradingDTO.getComment()
        );
        
        log.info("答案批改成功，答案ID: {}, 分数: {}/{}", 
                gradingDTO.getAnswerId(), gradingDTO.getScore(), examQuestion.getScore());
    }

    @Override
    @Transactional
    public void batchGradeStudent(GradingDTO.BatchGradingDTO batchGradingDTO) {
        Long teacherId = StpUtil.getLoginIdAsLong();
        log.info("教师 {} 批量批改学生 {} 在考试 {} 中的答案", teacherId, batchGradingDTO.getStudentId(), batchGradingDTO.getExamId());
        
        // 批量批改
        for (GradingDTO grading : batchGradingDTO.getGradings()) {
            gradeSingleAnswer(grading);
        }
        
        log.info("批量批改完成，学生ID: {}, 考试ID: {}", batchGradingDTO.getStudentId(), batchGradingDTO.getExamId());
    }
    
    @Override
    @Transactional
    public GradingResult completeStudentGradingBySession(Long sessionId) {
        Long teacherId = StpUtil.getLoginIdAsLong();
        log.info("教师 {} 通过sessionId {} 完成学生批改", teacherId, sessionId);
        
        // 1. 通过sessionId获取examId和studentId
        Map<String, Object> sessionInfo = examAnswersMapper.getExamAndStudentBySessionId(sessionId);
        if (sessionInfo == null) {
            throw new RuntimeException("考试会话不存在，sessionId: " + sessionId);
        }
        
        Long examId = (Long) sessionInfo.get("exam_id");
        Long studentId = (Long) sessionInfo.get("student_id");
        
        // 2. 检查是否还有未批改的主观题
        int unGradedCount = examAnswersMapper.countUnGradedSubjectiveAnswersBySession(sessionId);
        if (unGradedCount > 0) {
            throw new RuntimeException("还有 " + unGradedCount + " 道主观题未批改，无法完成批改");
        }
        
        // 3. 计算总分
        BigDecimal totalScore = examAnswersMapper.sumScoresBySession(sessionId);
        BigDecimal maxScore = examAnswersMapper.getMaxScoreByExam(examId);
        
        // 4. 检查是否已有成绩记录
        StudentGrade existingGrade = studentGradesMapper.selectGradeByExamAndStudent(examId, studentId);
        
        if (existingGrade != null) {
            // 更新现有记录
            existingGrade.setScore(totalScore);
            existingGrade.setComments("批改完成");
            studentGradesMapper.updateStudentGradeById(existingGrade);
        } else {
            // 创建新的成绩记录
            StudentGrade newGrade = new StudentGrade();
            newGrade.setExamId(examId);
            newGrade.setUserId(studentId);
            newGrade.setScore(totalScore);
            newGrade.setComments("批改完成");
            newGrade.setDisputeStatus("none");
            studentGradesMapper.insertStudentGrade(newGrade);
        }
        
        // 5. 计算题目数量
        int totalQuestions = examAnswersMapper.countAnswersBySession(sessionId);
        
        // 6. 返回结果
        GradingResult result = new GradingResult();
        result.setTotalScore(totalScore);
        result.setMaxScore(maxScore);
        result.setTotalQuestions(totalQuestions);
        result.setGradedQuestions(totalQuestions);
        result.setGradeStatus("completed");
        
        log.info("学生 {} 在考试 {} 中的批改完成（sessionId: {}），总分: {}/{}", studentId, examId, sessionId, totalScore, maxScore);
        
        return result;
    }

    @Override
    @Transactional
    public GradingResult completeStudentGrading(Long examId, Long studentId) {
        Long teacherId = StpUtil.getLoginIdAsLong();
        log.info("教师 {} 完成学生 {} 在考试 {} 的批改", teacherId, studentId, examId);
        
        // 1. 检查是否还有未批改的主观题
        int unGradedCount = examAnswersMapper.countUnGradedSubjectiveAnswers(examId, studentId);
        if (unGradedCount > 0) {
            throw new RuntimeException("还有 " + unGradedCount + " 道主观题未批改，无法完成批改");
        }
        
        // 2. 计算总分
        BigDecimal totalScore = examAnswersMapper.sumScoresByExamAndStudent(examId, studentId);
        BigDecimal maxScore = examAnswersMapper.getMaxScoreByExam(examId);
        
        // 3. 检查是否已有成绩记录
        StudentGrade existingGrade = studentGradesMapper.selectGradeByExamAndStudent(examId, studentId);
        
        if (existingGrade != null) {
            // 更新现有记录
            existingGrade.setScore(totalScore);
            existingGrade.setComments("批改完成");
            studentGradesMapper.updateStudentGradeById(existingGrade);
        } else {
            // 创建新的成绩记录
            StudentGrade newGrade = new StudentGrade();
            newGrade.setExamId(examId);
            newGrade.setUserId(studentId);
            newGrade.setScore(totalScore);
            newGrade.setComments("批改完成");
            newGrade.setDisputeStatus("none");
            studentGradesMapper.insertStudentGrade(newGrade);
        }
        
        // 4. 计算题目数量
        int totalQuestions = examAnswersMapper.countAnswersByExamAndStudent(examId, studentId);
        
        // 5. 返回结果
        GradingResult result = new GradingResult();
        result.setTotalScore(totalScore);
        result.setMaxScore(maxScore);
        result.setTotalQuestions(totalQuestions);
        result.setGradedQuestions(totalQuestions);
        result.setGradeStatus("completed");
        
        log.info("学生 {} 在考试 {} 中的批改完成，总分: {}/{}", studentId, examId, totalScore, maxScore);
        
        return result;
    }
    
    @Override
    @Transactional
    public AutoGradingResult triggerAutoGradingBySession(Long sessionId) {
        Long teacherId = StpUtil.getLoginIdAsLong();
        log.info("教师 {} 通过sessionId {} 触发自动批卷", teacherId, sessionId);
        
        // 1. 通过sessionId获取examId和studentId
        Map<String, Object> sessionInfo = examAnswersMapper.getExamAndStudentBySessionId(sessionId);
        if (sessionInfo == null) {
            throw new RuntimeException("考试会话不存在，sessionId: " + sessionId);
        }
        
        Long examId = (Long) sessionInfo.get("exam_id");
        Long studentId = (Long) sessionInfo.get("student_id");
        
        // 2. 调用自动批卷服务
        AutoGradingResult result = autoGradingService.autoGradeExam(examId, studentId);
        
        // 3. 检查是否已有成绩记录
        StudentGrade existingGrade = studentGradesMapper.selectGradeByExamAndStudent(examId, studentId);
        
        if (existingGrade == null) {
            // 创建新的成绩记录
            StudentGrade newGrade = new StudentGrade();
            newGrade.setExamId(examId);
            newGrade.setUserId(studentId);
            newGrade.setScore(BigDecimal.valueOf(result.getTotalScore()));
            newGrade.setComments("自动批改完成");
            newGrade.setDisputeStatus("none");
            studentGradesMapper.insertStudentGrade(newGrade);
        }
        
        log.info("自动批卷完成（sessionId: {}），学生 {} 在考试 {} 中，自动批改: {}题，需人工批改: {}题，得分: {}/{}",
                sessionId, studentId, examId, result.getAutoGradedQuestions(), 
                result.getManualGradedQuestions(), result.getTotalScore(), result.getMaxScore());
        
        return result;
    }

    @Override
    @Transactional
    public AutoGradingResult triggerAutoGrading(Long examId, Long studentId) {
        Long teacherId = StpUtil.getLoginIdAsLong();
        log.info("教师 {} 触发学生 {} 在考试 {} 的自动批卷", teacherId, studentId, examId);
        
        // 1. 调用自动批卷服务
        AutoGradingResult result = autoGradingService.autoGradeExam(examId, studentId);
        
        // 2. 检查是否已有成绩记录
        StudentGrade existingGrade = studentGradesMapper.selectGradeByExamAndStudent(examId, studentId);
        
        if (existingGrade == null) {
            // 创建新的成绩记录
            StudentGrade newGrade = new StudentGrade();
            newGrade.setExamId(examId);
            newGrade.setUserId(studentId);
            newGrade.setScore(BigDecimal.valueOf(result.getTotalScore()));
            newGrade.setComments("自动批改完成");
            newGrade.setDisputeStatus("none");
            studentGradesMapper.insertStudentGrade(newGrade);
        }
        
        log.info("自动批卷完成，学生 {} 在考试 {} 中，自动批改: {}题，需人工批改: {}题，得分: {}/{}",
                studentId, examId, result.getAutoGradedQuestions(), 
                result.getManualGradedQuestions(), result.getTotalScore(), result.getMaxScore());
        
        return result;
    }
}